#pragma once

#include "task/Task.hpp"
#include "task/PeriodicTask.hpp"
#include "task/PriorityTask.hpp"
#include "task/TimedTask.hpp"
#include "task/SuicideTask.hpp"

#include <memory>

namespace threadpool {

    class ThreadPool;

    enum class ThreadStatus {
        ThreadExit = false,   // 线程退出标志
        ThreadContinue = true // 线程继续标志
    };

    class TaskExecutor {

    public:

        /**
          * @brief  任务执行前的自定义行为
          * @note   用于处理自定义任务
          * @param  task 工作任务
          * @param  pool 线程池对象
          * @retval ThreadStatus 当前工作线程是否退出
          */
        virtual ThreadStatus customBeforeExecute(const std::shared_ptr<Task> &task, ThreadPool *pool) {
            return ThreadStatus::ThreadContinue;
        };

        /**
          * @brief  任务执行后的自定义行为
          * @note   用于处理自定义任务
          * @param  task 工作任务
          * @param  pool 线程池对象
          * @retval ThreadStatus 当前工作线程是否退出
          */
        virtual ThreadStatus customAfterExecute(const std::shared_ptr<Task> &task, ThreadPool *pool) {
            return ThreadStatus::ThreadContinue;
        };

        /**
          * @brief  任务执行前的默认行为
          * @note   包含线程池操作、内置任务处理和调用自定义任务处理等
          * @param  task 工作任务
          * @param  pool 线程池对象
          * @retval ThreadStatus 当前工作线程是否退出
          */
        virtual ThreadStatus defaultBeforeExecute(const std::shared_ptr<Task> &task, ThreadPool *pool);

        /**
          * @brief  任务执行后的默认行为
          * @note   包含线程池操作、内置任务处理和调用自定义任务处理等
          * @param  task 工作任务
          * @param  pool 线程池对象
          * @retval ThreadStatus 当前工作线程是否退出
          */
        virtual ThreadStatus defaultAfterExecute(const std::shared_ptr<Task> &task, ThreadPool *pool);

    };

}

#include "ThreadPool.hpp"

namespace threadpool {

    ThreadStatus TaskExecutor::defaultBeforeExecute(const std::shared_ptr<Task> &task, ThreadPool *pool) {
        if (task->getType() == "TimedTask") {
            auto *timed_task = dynamic_cast<TimedTask *>(task.get());
            std::this_thread::sleep_for(timed_task->getDelay());
        } else if (task->getType() == "PeriodicTask") {
            auto *periodic_task = dynamic_cast<PeriodicTask *>(task.get());
            std::this_thread::sleep_for(periodic_task->getPeriod());
        }
        return customBeforeExecute(task, pool);
    }

    ThreadStatus TaskExecutor::defaultAfterExecute(const std::shared_ptr<Task> &task, ThreadPool *pool) {
        if (task->getType() == "SuicideTask") {
            pool->submitPriorityTask(0, [&](const std::thread::id &id) {
                size_t index = 0;
                std::lock_guard<std::mutex> lock(pool->mutex_);
                for (; index < pool->workers_.size(); ++index) {
                    if (pool->workers_[index].get_id() == id) {
                        pool->workers_[index].join();
                    }
                }
                pool->workers_.erase(pool->workers_.begin() + index);
            }, std::this_thread::get_id());
            return ThreadStatus::ThreadExit;
        } else if (task->getType() == "PeriodicTask") {
            pool->queue_.push(task);
        }
        ThreadStatus status = customAfterExecute(task, pool);
        return status;
    }

}
